


namespace apeng {
    /**一些中文符号 */
    const fuhao = ['，', '。', '；', '！', '：', '【', '】', '…', '？', '“', '”', '—', '·', '、', '《', '》', '（', '）', '￥', '＠']

    export class Strings {

        public static indexOf(value: string, str: string, start: number = 0): number {
            return value.indexOf(str, start)
        }

        public static lastIndexOf(value: string, str: string): number {
            let index = this.indexOf(value, str)
            if (index == -1)
                return -1
            return index + str.length
        }

        public static after(value: string, find: string) {
            return value.substring(0, this.indexOf(value, find))
        }

        public static last(value: string, find: string) {
            return value.substring(this.lastIndexOf(value, find))
        }

        public static converText(text: string) {
            return {
                after: Strings.after(text, "{"),
                last: Strings.last(text, "}"),
            }
        }

        /**
         * 计算中文字符长度
         * 中文2个长度，英文1个长度
         * @param chars 
         * @returns 
         */
        public static chinaLength(chars: string): number {
            let fuhao_code = []
            for (let j = 0; j < fuhao.length; j++)
                fuhao_code.push(fuhao[j].charCodeAt(0))

            let sum = 0
            for (let i = 0; i < chars.length; i++) {
                let c = chars.charCodeAt(i)
                if ((c >= 0x0001 && c <= 0x007e) || (0xff60 <= c && c <= 0xff9f))
                    sum++
                //一些数字、字母、英文符号等
                else if (fuhao_code.indexOf(c) >= 0)
                    //一些中文符号
                    sum += 2
                else
                    sum += 2
            }

            return sum
        }

        /**截取中文字符的长度 */
        public static chinaSub(chars: string, length: number): string {
            let fuhao_code = []
            for (let j = 0; j < fuhao.length; j++)
                fuhao_code.push(fuhao[j].charCodeAt(0))

            let str = ""
            for (let i = 0; i < chars.length; i++) {
                let c = chars.charCodeAt(i)
                str += chars[i]
                let sub = 1
                if ((c >= 0x0001 && c <= 0x007e) || (0xff60 <= c && c <= 0xff9f))
                    sub = 1
                //一些数字、字母、英文符号等
                else if (fuhao_code.indexOf(c) >= 0)
                    //一些中文符号
                    sub = 2
                else
                    sub = 2

                length -= sub
                if (length <= 0)
                    break
            }
            return str
        }


        /**使用*号代替后面字符 */
        public static blur(value: string, hideCount: number): string {
            let str = ""
            for (let i = 0; i < hideCount; i++)
                str += "*"
            return value.substr(0, value.length - hideCount) + str
        }

        /**
         * 替换字符
         * @param value 
         * @param orgin 想要替换的
         * @param now 替换成
         * @param all 全部替换，反之第一个替换
         */
        public static replace(value: string, orgin: string, now: string, all: boolean) {
            // return value.replace(/orgin/g, now)
        }

        /**
         * 创建加密的 key
         * @param value 0~9可乱序排列，一般 使用当前毫秒时间
         * @returns 
         */
        public static createCodeByKey(value: string) {
            let nums: number[] = []
            let arr = (value + "").split("")
            for (let _arr of arr) {
                let __arr = Number(_arr)
                if (nums.indexOf(__arr) == -1)
                    nums.push(__arr)
            }
            for (let i = 0; i < 10; i++)
                if (nums.indexOf(i) == -1)
                    nums.push(i)

            //定义密钥，36个字母和数字
            return "AECDHFIJKLQMNOBPRXSTUVZWYG" + nums.join("")
        }

        /**加密 */
        public static encode(str: string, key: string) {
            if (!key)
                return str
            key = this.createCodeByKey(key)
            //定义密钥，36个字母和数字
            let len = key.length  //获取密钥的长度
            let a = key.split("")  //把密钥字符串转换为字符数组
            let s = "", b, b1, b2, b3  //定义临时变量
            for (let i = 0, strLen = str.length; i < strLen; i++) {  //遍历字符串
                b = str.charCodeAt(i)  //逐个提取每个字符，并获取Unicode编码值
                b1 = b % len  //求Unicode编码值得余数
                b = (b - b1) / len  //求最大倍数
                b2 = b % len  //求最大倍数的于是
                b = (b - b2) / len  //求最大倍数
                b3 = b % len  //求最大倍数的余数
                s += a[b3] + a[b2] + a[b1]  //根据余数值映射到密钥中对应下标位置的字符
            }
            return s //返回这些映射的字符
        }

        /**解密 */
        public static decode(str: string, key: string) {
            if (!key)
                return str
            key = this.createCodeByKey(key)
            //定义密钥，36个字母和数字
            let len = key.length  //获取密钥的长度
            let b, b1, b2, b3, d = 0, s  //定义临时变量
            b = Math.floor(str.length / 3)  //获取数组的长度
            s = new Array(b)  //计算加密字符串包含的字符数，并定义数组
            for (let i = 0; i < b; i++) {  //以数组的长度循环次数，遍历加密字符串
                b1 = key.indexOf(str.charAt(d))  //截取周期内第一个字符串，计算在密钥中的下标值
                d++
                b2 = key.indexOf(str.charAt(d))  //截取周期内第二个字符串，计算在密钥中的下标值
                d++
                b3 = key.indexOf(str.charAt(d))  //截取周期内第三个字符串，计算在密钥中的下标值
                d++
                s[i] = b1 * len * len + b2 * len + b3  //利用下标值，反推被加密字符的Unicode编码值
            }
            b = String.fromCharCode(...s) // 用fromCharCode()算出字符串
            return b;  //返回被解密的字符串
        }

        /* *
         * 压缩字符串
         * 手动拷贝出来 解析不对（符合加密需求）
         */
        public static compress(strNormalString: string) {
            let strCompressedString = ""
            let ht = new Array()
            for (let i = 0; i < 128; i++)
                ht[i] = i

            let used = 128
            let intLeftOver = 0
            let intOutputCode = 0
            let pcode = 0
            let ccode = 0
            let k = 0

            for (let i = 0; i < strNormalString.length; i++) {
                ccode = strNormalString.charCodeAt(i)
                k = (pcode << 8) | ccode
                if (ht[k] != null)
                    pcode = ht[k]
                else {
                    intLeftOver += 12
                    intOutputCode <<= 12
                    intOutputCode |= pcode
                    pcode = ccode
                    if (intLeftOver >= 16) {
                        strCompressedString += String.fromCharCode(intOutputCode >> (intLeftOver - 16))
                        intOutputCode &= (Math.pow(2, (intLeftOver - 16)) - 1)
                        intLeftOver -= 16
                    }
                    if (used < 4096) {
                        used++
                        ht[k] = used - 1
                    }
                }
            }

            if (pcode != 0) {
                intLeftOver += 12
                intOutputCode <<= 12
                intOutputCode |= pcode
            }

            if (intLeftOver >= 16) {
                strCompressedString += String.fromCharCode(intOutputCode >> (intLeftOver - 16))
                intOutputCode &= (Math.pow(2, (intLeftOver - 16)) - 1)
                intLeftOver -= 16
            }

            if (intLeftOver > 0) {
                intOutputCode <<= (16 - intLeftOver)
                strCompressedString += String.fromCharCode(intOutputCode)
            }

            return strCompressedString
        }

        /* *
         * 解压缩字符串
         */
        public static decompress(strCompressedString: string) {
            let strNormalString = ""
            let ht = new Array()

            for (let i = 0; i < 128; i++)
                ht[i] = String.fromCharCode(i)

            let used = 128
            let intLeftOver = 0
            let intOutputCode = 0
            let ccode = 0
            let pcode = 0
            let key = 0

            for (let i = 0; i < strCompressedString.length; i++) {
                intLeftOver += 16
                intOutputCode <<= 16
                intOutputCode |= strCompressedString.charCodeAt(i)

                while (1) {
                    if (intLeftOver >= 12) {
                        ccode = intOutputCode >> (intLeftOver - 12)
                        if (typeof (key = ht[ccode]) != "undefined") {
                            strNormalString += key
                            if (used > 128)
                                ht[ht.length] = ht[pcode] + (key as any).substr(0, 1)
                            pcode = ccode
                        } else {
                            key = ht[pcode] + ht[pcode].substr(0, 1)
                            strNormalString += key
                            ht[ht.length] = ht[pcode] + (key as any).substr(0, 1)
                            pcode = ht.length - 1
                        }

                        used++
                        intLeftOver -= 12
                        intOutputCode &= (Math.pow(2, intLeftOver) - 1)
                    } else
                        break
                }
            }
            return strNormalString
        }

    }
}